home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / The World of Computer Software.iso / minioop.zip / MINIOOP.SCM next >
Text File  |  1993-01-18  |  5KB  |  154 lines

  1.  
  2. ; Minimal object support for Scheme
  3. ;
  4. ;
  5. ; Sample use:  We want to have a `print' procedure that behaves like `write'
  6. ; except that numbers are written in base 2, dot notation is used
  7. ; for lists and a special format is used for VEHICLE structures.
  8. ;
  9. ;
  10. ;    (define (default? x) #t)
  11. ;
  12. ;    (define-method default? (print obj) ; order of definitions is important...
  13. ;      (write obj))                      ; search is done from last to first
  14. ;                                        ; so this is the last to be tested.
  15. ;
  16. ;    (define-method number? (print obj)
  17. ;      (display "#b")
  18. ;      (display (number->string obj 2)))
  19. ;
  20. ;    (define-method pair? (print obj)
  21. ;      (display "(")
  22. ;      (print (car obj))
  23. ;      (display " . ")
  24. ;      (print (cdr obj))
  25. ;      (display ")"))
  26. ;
  27. ;    (define-struct vehicle registration-id weight nb-wheels)
  28. ;
  29. ;    (define-method vehicle? (print obj)
  30. ;      (display "#<VEHICLE id:")
  31. ;      (print (vehicle-registration-id obj))
  32. ;      (display ">"))
  33. ;
  34. ;    (print (list 1 'hello '(2 3) (make-vehicle 14 2000 4)))  -->
  35. ;
  36. ;       (#b1 . (hello . ((#b10 . (#b11 . ())) . (#<VEHICLE id:#b1110> . ()))))
  37. ;
  38. ;
  39. ; Note: This code was written for Gambit.  The `##' prefix on identifiers
  40. ;       should be removed for other Scheme systems.
  41.  
  42. (##define-macro (define-method . args)
  43.  
  44.   (define (err) (error "Ill-formed `define-method'") #f)
  45.  
  46.   (define (def-method classes name parms body)
  47.     `(DEFINE ,name
  48.        (##MAKE-METHOD ',name
  49.                       (LAMBDA ,parms ,@body)
  50.                       ,@(map (lambda (x) `(LAMBDA () ,x)) classes))))
  51.  
  52.   (let loop ((args args) (classes '()))
  53.     (if (pair? args)
  54.       (let ((rest (cdr args)) (arg (car args)))
  55.         (cond ((symbol? arg)
  56.                (loop rest (cons arg classes)))
  57.               ((pair? arg)
  58.                (let ((name (car arg)) (parms (cdr arg)))
  59.                  (if (and (pair? classes) (symbol? name) (pair? rest))
  60.                    (def-method classes name parms rest)
  61.                    (err))))
  62.               (else
  63.                (err))))
  64.       (err))))
  65.  
  66. (define (##make-method name proc . classes)
  67.   (let ((method-descr (assq name ##method-descriptors)))
  68.  
  69.     (if (not method-descr) ; first definition?
  70.  
  71.       ; create new method descriptor...
  72.  
  73.       (let ((method-descr
  74.               (cons name (cons #f (map (lambda (x) (cons x proc)) classes)))))
  75.  
  76.         (define (generic-proc self . rest)
  77.           (let loop ((l (cddr method-descr)))
  78.             (if (pair? l)
  79.               (let ((entry (car l)))
  80.                 (if (((car entry)) self)
  81.                   (apply (cdr entry) self rest)
  82.                   (loop (cdr l))))
  83.               (error "Method is not defined for this object:"
  84.                      (car method-descr) self))))
  85.  
  86.         (set-car! (cdr method-descr) generic-proc)
  87.  
  88.         (set! ##method-descriptors (cons method-descr ##method-descriptors))
  89.  
  90.         generic-proc)
  91.  
  92.       ; update method descriptor if it existed before...
  93.  
  94.       (let ()
  95.  
  96.         (define (add-entry class)
  97.           (let ((new-entry (cons class proc)))
  98.             (let loop ((l (cddr method-descr)))
  99.               (let ((entry (car l)) (rest (cdr l)))
  100.                 (cond ((eq? (class) ((car entry))) ; replace entry
  101.                        (set-car! l new-entry))
  102.                       ((pair? rest)
  103.                        (loop rest))
  104.                       (else ; add at head of dispatch table
  105.                        (set-cdr! (cdr method-descr)
  106.                          (cons new-entry (cddr method-descr)))))))))
  107.  
  108.         (for-each add-entry classes)
  109.  
  110.         (cadr method-descr)))))
  111.  
  112. (define ##methlasses)
  113.  
  114.         (cadr method-descr)))))
  115.  
  116. (define ##method-descriptors '())
  117.  
  118.  
  119. ; `Define-struct' is not strictly necessary for the object system but
  120. ; it is useful to define new data types.
  121.  
  122. (##define-macro (define-struct name . fields)
  123.  
  124.   (define (err) (error "Ill-formed `define-struct'") #f)
  125.  
  126.   (define (sym . strings) (string->symbol (apply string-append strings)))
  127.  
  128.   (if (symbol? name)
  129.     (let ((name-str (symbol->string name)))
  130.       (let loop ((l1 fields) (l2 '()) (i 1))
  131.         (if (pair? l1)
  132.           (let ((rest (cdr l1)) (field (car l1)))
  133.             (if (symbol? field)
  134.               (let* ((field-str (symbol->string field))
  135.                      (field-ref (sym name-str "-" field-str))
  136.                      (field-set! (sym name-str "-" field-str "-set!")))
  137.                 (loop rest
  138.                       (cons `(DEFINE (,field-set! X Y) (VECTOR-SET! X ,i Y))
  139.                             (cons `(DEFINE (,field-ref X) (VECTOR-REF X ,i))
  140.                                   l2))
  141.                       (+ i 1)))
  142.               (err)))
  143.           `(BEGIN
  144.              ,@l2
  145.              (DEFINE ,(sym "##tag-" name-str) (LIST ',name))
  146.              (DEFINE (,(sym "make-" name-str) ,@fields)
  147.                (VECTOR ,(sym "##tag-" name-str) ,@fields))
  148.              (DEFINE (,(sym name-str "?") X)
  149.                (AND (VECTOR? X) (= (VECTOR-LENGTH X) ,i)
  150.                     (EQ? (VECTOR-REF X 0) ,(sym "##tag-" name-str))))))))
  151.     (err)))
  152.  
  153.  
  154.